﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FrameworkLib.Facades;
using FrameworkLib.Repository;
using GestionePolveriLib.BL;
using GestionePolveri2.DAL;
using System.Linq.Expressions;
using FrameworkLib.Filters;
using LinqKit;
using GestionePolveriLib.BL.Filters;

namespace GestionePolveriLib.Facades
{
    public class PrenotazioniFacade : FacadeBase<GestionePolveriEntities>, IFacadeBase<Prenotazione>
    {
        GestionePolveriEntities context = null;

        public PrenotazioniFacade()
        {
            context = this.GetContext();
        }

        public PrenotazioniFacade(string connectionString)
        {
            context = this.GetContext(connectionString);
        }

        public IEnumerable<Prenotazione> Get()
        {
            IEnumerable<Prenotazione> retValue = null;

            try
            {
                var objs = from x in context.Prenotazioni
                           orderby x.Data descending
                           select new Prenotazione { 
                              ID = x.IDPrenotazione,
                              Data = x.Data,
                              IDOperatore = x.IDOperatore,
                              IDPolvere = x.IDPolvere,
                              Tipo = (OperationTypes)x.IDOperazione,
                              Quantita = x.Quantita,
                              Note = x.Note,
                              IsAnnullata = x.IsAnnullata,
                              IDOperatoreAnnullo = x.IDOperatoreAnnullo.Value,
                              DataAnnullo = x.DataAnnullo.Value,
                              NoteAnnullo = x.NoteAnnullo
                           };

                if (objs.Any())
                {
                    retValue = objs;                
                }
            }
            catch (Exception ex)
            {
                this.LastExceptionOccurred = ex;
                throw ex;
            }

            return retValue;
        }

        public bool Add(Prenotazione value)
        {
            bool retValue = false;

            try
            {
                Prenotazioni obj = new Prenotazioni();
                obj.IDOperatore = value.IDOperatore;
                obj.IDPolvere = value.IDPolvere;
                obj.IDOperazione = (int)value.Tipo;
                obj.Data = value.Data;
                obj.Note = value.Note;
                obj.Quantita = value.Quantita;
                obj.IsAnnullata = value.IsAnnullata;

                context.Prenotazioni.AddObject(obj);
                context.SaveChanges();

                value.ID = obj.IDPrenotazione;

                retValue = true;
            }
            catch (Exception ex)
            {
                this.LastExceptionOccurred = ex;
                throw ex;
            }

            return retValue;
        }

        public bool Modify(Prenotazione value)
        {
            bool retValue = false;

            try
            {
                var objs = from x in context.Prenotazioni
                          where x.IDPrenotazione == value.ID
                          select x;

                if (objs.Any())
                {
                    Prenotazioni obj = objs.FirstOrDefault();
                    obj.IDOperatore = value.IDOperatore;
                    obj.IDPolvere = value.IDPolvere;
                    obj.IDOperazione = (int)value.Tipo;
                    obj.Note = value.Note;
                    obj.Quantita = value.Quantita;
                    obj.IsAnnullata = value.IsAnnullata;

                    if (value.IsAnnullata)
                    {
                        obj.IDOperatoreAnnullo = value.IDOperatoreAnnullo;
                        obj.DataAnnullo = value.DataAnnullo;
                        obj.NoteAnnullo = value.NoteAnnullo;
                    }

                    context.SaveChanges();

                    retValue = true;
                }

               
            }
            catch (Exception ex)
            {
                this.LastExceptionOccurred = ex;
                throw ex;
            }

            return retValue;
        }

        public bool AddOrModify(Prenotazione value)
        {
            bool retValue = false;

            try
            {
                var obj = from x in context.Prenotazioni
                          where x.IDPrenotazione == value.ID
                          select x;

                if (obj.Any())
                {
                    retValue = Modify(value);
                }
                else
                {
                    retValue = Add(value);
                }
            }
            catch (Exception ex)
            {
                this.LastExceptionOccurred = ex;
                throw ex;
            }

            return retValue;
        }

        public bool Delete(Prenotazione value)
        {
            bool retValue = false;

            try
            {
                var objs = from x in context.Prenotazioni
                           where x.IDPrenotazione == value.ID
                           select x;

                if (objs.Any())
                {
                    //using (RepositoryBase<GestionePolveriEntities> rep = this.Repository)
                    //{
                    //    rep.Delete<StoricoOperazioni>(objs.FirstOrDefault());
                    //}

                    Prenotazioni obj = objs.FirstOrDefault();
                    context.Prenotazioni.DeleteObject(obj);
                    context.SaveChanges();

                    retValue = true;
                }
            }
            catch (Exception ex)
            {
                this.LastExceptionOccurred = ex;
                throw ex;
            }

            return retValue;
        }

        public IEnumerable<Prenotazione> Get(Expression<Func<Prenotazione, bool>> filter = null)
        {
            IEnumerable<Prenotazione> retValue = null;

            try
            {
                var objs = (from x in context.Prenotazioni
                           select new Prenotazione
                           {
                               ID = x.IDPrenotazione,
                               Data = x.Data,
                               IDOperatore = x.IDOperatore,
                               IDPolvere = x.IDPolvere,
                               Tipo = (OperationTypes)x.IDOperazione,
                               Quantita = x.Quantita,
                               Note = x.Note,
                               IsAnnullata = x.IsAnnullata,
                               IDOperatoreAnnullo = x.IDOperatoreAnnullo.Value,
                               DataAnnullo = x.DataAnnullo.Value,
                               NoteAnnullo = x.NoteAnnullo
                           }).Where(filter);

                if (objs.Any())
                {
                    retValue = objs;
                }
            }
            catch (Exception ex)
            {
                this.LastExceptionOccurred = ex;
                throw ex;
            }

            return retValue;
        }

        public List<Prenotazione> Get(FilterBase<Prenotazioni> filter, ElencoPrenotazioniFilterBag filterBag)
        {
            List<Prenotazione> retValue = null;

            try
            {
                var objs = from x in context.Prenotazioni.AsExpandable().Where(filter.SetUpFilter())
                           join ap in context.AnagPolveri on x.IDPolvere equals ap.IDPolvere into AnagPolveriRJ
                           from ap in AnagPolveriRJ.DefaultIfEmpty()
                           orderby x.Data descending
                           select new Prenotazione
                           {
                               ID = x.IDPrenotazione,
                               Data = x.Data,
                               IDOperatore = x.IDOperatore,
                               IDPolvere = x.IDPolvere,
                               Tipo = (OperationTypes)x.IDOperazione,
                               Quantita = x.Quantita,
                               Note = x.Note,
                               IsAnnullata = x.IsAnnullata,
                               CodicePolvere = x.AnagPolveri.CodicePolvere,
                               OperatoreName = x.aspnet_Users.UserName,
                               IDOperatoreAnnullo = x.IDOperatoreAnnullo.Value,
                               DataAnnullo = x.DataAnnullo.Value,
                               NoteAnnullo = x.NoteAnnullo,
                               OperatoreNameAnnullo = (from u in context.aspnet_Users where u.UserId == x.IDOperatoreAnnullo select u.UserName).FirstOrDefault()
                           };

                if (objs.Any())
                {
                    retValue = objs.ToList();

                    LoadInformazioniAccessorie(retValue);

                    // merdata per non scrivere una stored procedure che va a mettere riparo
                    // alla mancata possibilità di scrivere correttamente da linq una right outer join...
                    if (!string.IsNullOrWhiteSpace(filterBag.CodiceColore))
                    {
                        // uso la filterbag per applicare il filtro in memoria all'intero set di dati caricato dal db...
                        retValue = retValue.Where(m => !string.IsNullOrWhiteSpace(m.ColoriAbbinati) && m.ColoriAbbinati.Contains(filterBag.CodiceColore)).ToList();
                    }
                }
            }
            catch (Exception ex)
            {
                this.LastExceptionOccurred = ex;
                throw ex;
            }

            return retValue;
        }

        public List<Prenotazione> Get(FilterBase<Prenotazioni> filter)
        {
            List<Prenotazione> retValue = null;

            try
            {
                var objs = from x in context.Prenotazioni.AsExpandable().Where(filter.SetUpFilter())
                           join ap in context.AnagPolveri on x.IDPolvere equals ap.IDPolvere into AnagPolveriRJ
                           from ap in AnagPolveriRJ.DefaultIfEmpty()
                           orderby x.Data descending
                           select new Prenotazione
                           {
                               ID = x.IDPrenotazione,
                               Data = x.Data,
                               IDOperatore = x.IDOperatore,
                               IDPolvere = x.IDPolvere,
                               Tipo = (OperationTypes)x.IDOperazione,
                               Quantita = x.Quantita,
                               Note = x.Note,
                               IsAnnullata = x.IsAnnullata,
                               CodicePolvere = x.AnagPolveri.CodicePolvere,
                               OperatoreName = x.aspnet_Users.UserName,
                               IDOperatoreAnnullo = x.IDOperatoreAnnullo.Value,
                               DataAnnullo = x.DataAnnullo.Value,
                               NoteAnnullo = x.NoteAnnullo,
                               OperatoreNameAnnullo = (from u in context.aspnet_Users where u.UserId == x.IDOperatoreAnnullo select u.UserName).FirstOrDefault()
                           };

                if (objs.Any())
                {
                    retValue = objs.ToList();

                    LoadInformazioniAccessorie(retValue);
                }
            }
            catch (Exception ex)
            {
                this.LastExceptionOccurred = ex;
                throw ex;
            }

            return retValue;
        }

        public bool AnnullaPrenotazione(Prenotazione value)
        {
            bool retValue = false;

            try
            {
                Prenotazione obj = this.Get(x => x.ID == value.ID).SingleOrDefault();

                if (obj != null)
                {
                    obj.IsAnnullata = true;
                    obj.IDOperatoreAnnullo = value.IDOperatoreAnnullo;
                    obj.DataAnnullo = value.DataAnnullo;
                    obj.NoteAnnullo = value.NoteAnnullo;

                    retValue = Modify(obj);
                }
            }
            catch (Exception ex)
            {
                this.LastExceptionOccurred = ex;
                throw ex;
            }

            return retValue;
        }

        private void LoadInformazioniAccessorie(IEnumerable<Prenotazione> retValue)
        {
            List<LookUp_FamiglieColori_ColoriAbbinati_Result> mmm = (List<LookUp_FamiglieColori_ColoriAbbinati_Result>)FrameworkLib.Utilities.Singleton<GestionePolveriLib.Cache.LookUpData>.Instance.GetData("LookupFamiglie");

            LottoFacade lf = new LottoFacade();
            foreach (Prenotazione p in retValue)
            {
                LookUp_FamiglieColori_ColoriAbbinati_Result r = mmm.Find(x => x.IDPolvere == p.IDPolvere);

                if (r != null)
                {
                    p.ColoriAbbinati = r.ColoriAbbinati;
                }
            }
        }

        public double GetQuantitaImpegnata(int idPolvere)
        {
            double retValue = 0;

            try
            {
                var obj = (from pr in context.Prenotazioni where pr.IDPolvere == idPolvere where !pr.IsAnnullata select (double?)pr.Quantita).Sum() ?? 0;
                retValue = (double)obj;
            }
            catch
            {
                retValue = 0;
            }
            
            return retValue;
        }

        public bool CheckPrenotazione(int idPolvere)
        {
            bool retValue = false;

            try
            {
                var obj = from pr in context.Prenotazioni where pr.IDPolvere == idPolvere where !pr.IsAnnullata select pr;
                if (obj.Any())
                {
                    retValue = true;
                }
            }
            catch
            {
                retValue = false;
            }

            return retValue;
        }
    }
}
